#include <simulation.h>
#include <config.h>
#include <time.h>
#include <stdlib.h>
#include <pthread.h>
#include <mqueue.h>
#include <fcntl.h>           /* Pour les constantes O_* */
#include <sys/stat.h>        /* Pour les constantes « mode » */
#include <unistd.h>

/* Seuil pour la simulation :*/
/* _SEUIL chances sur 1000 d'obtenir un evenement favorable lors de la lecture d'un capteur */
#define _SEUIL 900

/* index des threads lancés et des BaL ouvertes */
#define DIM 0
#define ERR 1

/* la simulation des IT se fait grace a des thread qui envoient aléatoirement des messages au threads concernés*/
void* handler_AU();
void* handler_Dim();

static pthread_mutex_t mutexClapet;
static int EtatDuClapet;
static mqd_t bal[2];
static pthread_t threads[2];
	
void LancerSimu()
{
	pthread_attr_t attr;
	struct sched_param schedParam;
	
	/* init du clapet */
	EtatDuClapet=CLAPET_F;
	srand(time(0));
	pthread_mutex_init(&mutexClapet ,NULL);
	
	/* init de la simulation des interruptions */
	struct mq_attr param={0,10,sizeof(MSG_dimension),0};
	bal[DIM]=mq_open(BAL_DIMENSION,O_CREAT,PERMISSION,&param);
					
	pthread_attr_init(&attr);
	pthread_attr_setschedpolicy(& attr, SCHED_FIFO);
	pthread_attr_setinheritsched(& attr, PTHREAD_EXPLICIT_SCHED);
	schedParam.sched_priority =PRIO_THR_XXL;
	pthread_attr_setschedparam(& attr, & schedParam);
	pthread_create(&(threads[DIM]), &attr,handler_Dim,NULL);
	pthread_create(&(threads[ERR]), &attr,handler_AU,NULL);

	return;
}

void ArreterSimu()
{
	pthread_cancel(threads[DIM]);
	mq_close(bal[DIM]);
	mq_unlink(BAL_DIMENSION);
	
	pthread_cancel(threads[ERR]);

	pthread_mutex_destroy(&mutexClapet);
}

void* handler_AU()
/* toute les 120 secondes, 1/10 chance d'avoir un arret d'urgence */
{
	bal[ERR]=mq_open(BAL_versErreur,O_WRONLY);
	unsigned int nb;
	while(1)
	{
		sleep(120);
		nb=rand()%1000;
		if(EtatClapet()==CLAPET_O)
		{
			if(nb>=_SEUIL)
			{
				MSG_versErreur msg;
				msg.source=T_AU;
				msg.message=AR_URG;
				msg.heure=time(NULL);
				msg.numLot=0;
				msg.cartonEnCours=0;
				mq_send(bal[ERR],(char*)&msg,sizeof(MSG_versErreur),PRIO_MSG_XL);
			}
		}
	}
	pthread_exit(0);	 
}

void* handler_Dim()
{
	bal[DIM]=mq_open(BAL_DIMENSION,O_WRONLY);
	unsigned int nb;
	while(1)
	{
		sleep(4);
		nb=rand()%1000;
		if(EtatClapet()==CLAPET_O)
		{
			/* envoi d'une présence piece */
			if(nb<=_SEUIL)
			{
				MSG_dimension msg; 
				/* envoie d'une piece bonne */
				if(nb<(_SEUIL-100))
				{
					msg.etat_piece=DIMENSION_OK;
					mq_send(bal[DIM],(char*)&msg,sizeof(MSG_dimension),PRIO_MSG_L); 
				}
				/* envoi d'une piece defectueuse */
				else
				{
					msg.etat_piece=DIMENSION_NOK;
					mq_send(bal[DIM],(char*)&msg,sizeof(MSG_dimension),PRIO_MSG_L); 
				}
			
			}
		}
	}
	pthread_exit(0);	 
}

int PresencePalette()
{
	unsigned int nb;
	nb=rand()%1000;
	if(nb>=_SEUIL)
	{
		return PALETTE_NOK;
	} 
	else
	{
		return PALETTE_OK;
	}
}

int EtatImpression()
{
	unsigned int nb;
	nb=rand()%1000;
	if(nb>=_SEUIL)
	{
		return IMPRESSION_NOK;
	} 
	else
	{
		return IMPRESSION_OK;
	}
}

int PresenceCarton()
{
	unsigned int nb;
	nb=rand()%1000;
	if(nb>=_SEUIL)
	{
		return CARTON_NOK;
	} 
	else
	{
		return CARTON_OK;
	}
}


int EtatClapet()
{
	int etat;
	pthread_mutex_lock(&mutexClapet);
	etat = EtatDuClapet;
	pthread_mutex_unlock(&mutexClapet);
	return etat;
}

void OuvertureClapet()
{
	pthread_mutex_lock(&mutexClapet);
	EtatDuClapet = CLAPET_O;
	pthread_mutex_unlock(&mutexClapet);
	return;
}

void FermetureClapet()
{	
	pthread_mutex_lock(&mutexClapet);
	EtatDuClapet = CLAPET_F;
	pthread_mutex_unlock(&mutexClapet);
	return;
}
